// vPresent is an immersive presentation creation and display application.
// Copyright (C) 2007 by Infiscape Corporation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

#include <iostream>
#include <boost/bind.hpp>

#if defined(__APPLE__)
#  include <OpenGL/gl.h>
#else
#  include <GL/gl.h>
#endif

#include <OpenSG/OSGTypeFactory.h>
#include <OpenSG/OSGRemoteAspect.h>

#include "RenderServer.h"


namespace
{

bool aspectCallback(const std::string& prefix,
                    OSG::FieldContainerPtrConstArg fcp)
{
   std::cout << prefix << fcp->getType().getName() << " "
             << OSG::getContainerId(fcp) << std::endl;
}

}

namespace vp
{

RenderServer::RenderServer(const std::string& name, vp::WindowPtr window,
                           const std::string& connectionType,
                           const std::string& address,
                           const OSG::UInt32 servicePort,
                           const std::string& serviceGroup,
                           const bool exitOnError)
   : mName(name)
   , mWindow(window)
   , mConnectionType(connectionType)
   , mAddress(address)
   , mServicePort(servicePort)
   , mServiceGroup(serviceGroup)
   , mExitOnError(exitOnError)
{
   mRenderAction = RenderActionPtr(OSG::RenderTraversalAction::create());
   mRenderConnection =
      mWindow->connectRenderSlot(boost::bind(&RenderServer::render, this));
}

void RenderServer::run()
{
   OSG::WindowRefPtr window = mWindow->getWindow();
   window->activate();

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_NORMALIZE);

   // create the cluster server
   mServer = ClusterServerPtr(new OSG::ClusterServer(window, mName,
                                                     mConnectionType,
                                                     mAddress /*,
                                                     mServicePort,
                                                     mServiceGroup */));

   // start the server
   mServer->start();
/*
   OSG::RemoteAspect* aspect = mServer->getRemoteAspect();

   // Register interest for all types.
   // NOTE: We have to be careful about this. OSG::RemoteAspect only allows
   // for one callback for each of changed, destroyed, and created. In
   // particular, OSG::ClusterServer depends on having change notification for
   // OSG::ClusterWindow and subclasses thereof, so we CANNOT register a
   // change callback.
   const OSG::UInt32 type_count(OSG::TypeFactory::the()->getNumTypes());
   for ( OSG::UInt32 i = 0; i < type_count; ++i )
   {
      OSG::FieldContainerType* fct =
         OSG::FieldContainerFactory::the()->findType(i);

      if ( fct )
      {
//         aspect->registerDestroyed(
//            *fct, boost::bind(&aspectCallback, "Destroyed: ", _1)
//         );
         aspect->registerCreated(
            *fct, boost::bind(&aspectCallback, "Created: ", _1)
         );
      }
   }
*/
   mWindow->show();
   mWindow->runEventLoop();
}

void RenderServer::render()
{
   try
   {
      mServer->render(mRenderAction.get());
      OSG::Thread::getCurrentChangeList()->clear();
   }
   catch (std::exception& ex)
   {
      if ( mExitOnError )
      {
         std::cerr << ex.what() << std::endl;
         mRenderConnection.disconnect();
         mWindow->close();
         mWindow = vp::WindowPtr();
      }
      else
      {
         // Stop the server until another client connects.
         mServer->stop();

         // Hide our window until another client connets.
         mWindow->hide();

         // Block until another client connects.
         mServer->start();

         // Show our window again now that we have a connected client.
         mWindow->show();
      }
   }
}

}
